import pytest
from unittest.mock import MagicMock, patch
import requests


# 模拟API客户端（零网络调用）
class CvmClient:
    def __init__(self):
        self.responses = {
            # 基础响应
            "Success": {"Response": {"RequestId": "mock-req-123"}},

            # 参数验证错误
            "MissingParameter.InstanceId": {
                "Response": {"Error": {"Code": "MissingParameter.InstanceId"}}
            },
            "MissingParameter.Password": {
                "Response": {"Error": {"Code": "MissingParameter.Password"}}
            },
            "InvalidPassword.Length": {
                "Response": {"Error": {"Code": "InvalidPassword.Length"}}
            },
            "InvalidPassword.SpecialCharacter": {
                "Response": {"Error": {"Code": "InvalidPassword.SpecialCharacter"}}
            },
            "InvalidInstanceId.NotFound": {
                "Response": {"Error": {"Code": "InvalidInstanceId.NotFound"}}
            },

            # 资源状态错误
            "OperationDenied.InstanceStatus": {
                "Response": {"Error": {"Code": "OperationDenied.InstanceStatus"}}
            },

            # 权限与认证错误
            "AuthFailure.UnauthorizedInstance": {
                "Response": {"Error": {"Code": "AuthFailure.UnauthorizedInstance"}}
            },

            # 重复提交错误
            "ClientTokenConflict": {
                "Response": {"Error": {"Code": "ClientTokenConflict"}}
            }
        }

    def reset_password(self, instance_id, password, key_names=None, keep_login_password=False, client_token=None):
        # 参数校验逻辑
        if not instance_id or not isinstance(instance_id, str):
            return self.responses["MissingParameter.InstanceId"]
        if not password or not isinstance(password, str):
            return self.responses["MissingParameter.Password"]
        if len(password) < 8 or len(password) > 30:
            return self.responses["InvalidPassword.Length"]
        if not any(c.isupper() for c in password) or not any(c.isdigit() for c in password):
            return self.responses["InvalidPassword.SpecialCharacter"]

        # 资源状态检查
        if instance_id.startswith("ins-stopped"):
            return self.responses["OperationDenied.InstanceStatus"]

        # 权限检查
        if instance_id.startswith("unauthorized-"):
            return self.responses["AuthFailure.UnauthorizedInstance"]

        # 重复提交检查
        if client_token == "conflict-token":
            return self.responses["ClientTokenConflict"]

        # 默认成功响应
        return self.responses["Success"]


# 测试用例
class TestResetInstancePassword:
    @pytest.fixture
    def client(self):
        return CvmClient()

    # 参数验证类错误
    @pytest.mark.parametrize("instance_id,password,expected_code", [
        (None, "P@ssw0rd!", "MissingParameter.InstanceId"),  # 缺少实例ID
        ("ins-123", None, "MissingParameter.Password"),  # 缺少密码
        ("ins-123", "short", "InvalidPassword.Length"),  # 密码过短
        ("ins-123", "NO_DIGIT", "InvalidPassword.SpecialCharacter"),  # 缺少数字
        ("ins-123", "no_upper", "InvalidPassword.SpecialCharacter")  # 缺少大写字母
    ])
    def test_invalid_params(self, client, instance_id, password, expected_code):
        response = client.reset_password(instance_id, password)
        assert response["Response"]["Error"]["Code"] == expected_code

    # 资源状态类错误
    @pytest.mark.parametrize("instance_id,expected_code", [
        ("ins-stopped", "OperationDenied.InstanceStatus"),  # 实例已停止
        ("ins-starting", "OperationDenied.InstanceStatus")  # 实例启动中
    ])
    def test_resource_status(self, client, instance_id, expected_code):
        response = client.reset_password(instance_id, "P@ssw0rd!123")
        assert response["Response"]["Error"]["Code"] == expected_code

    # 权限与认证类错误
    @pytest.mark.parametrize("instance_id,expected_code", [
        ("unauthorized-instance", "AuthFailure.UnauthorizedInstance"),  # 无权限实例
        ("invalid-instance-id", "InvalidInstanceId.NotFound")  # 无效实例ID
    ])
    def test_auth_errors(self, client, instance_id, expected_code):
        response = client.reset_password(instance_id, "P@ssw0rd!123")
        assert response["Response"]["Error"]["Code"] == expected_code

    # 重复提交类错误
    def test_client_token_conflict(self, client):
        response = client.reset_password("ins-123", "P@ssw0rd!123", client_token="conflict-token")
        assert response["Response"]["Error"]["Code"] == "ClientTokenConflict"

    # 正常用例
    def test_success(self, client):
        response = client.reset_password(
            instance_id="ins-123",
            password="P@ssw0rd!123",
            key_names=["key-123"],
            keep_login_password=True,
            client_token="unique-token"
        )
        assert response["Response"]["RequestId"] == "mock-req-123"
        assert "Error" not in response["Response"]


# 执行测试
if __name__ == "__main__":
    pytest.main(["-v", "--color=yes"])